#pragma once
#include <boost/shared_ptr.hpp>
#include "Map.h"
#include "Plan.h"

class Node
{
public:
	Node(const boost::shared_ptr<const Map>& map, int nbPoints)
		: _predecessor(), _action(), _map(map), _nbPoints(nbPoints), _id(nextID++)
	{
		// Constructor for initial node only (no predecessor and no action)
	}

	Node(const boost::shared_ptr<const Node>& predecessor, Action action, const boost::shared_ptr<const Map>& newMap, int nbPoints)
		: _predecessor(predecessor), _action(action), _map(newMap), _nbPoints(nbPoints), _id(nextID++)
	{
  }

  ~Node()
  {
  }

	bool operator<(const Node& other) const
	{
		return _nbPoints < other._nbPoints;
	}
	bool operator>(const Node& other) const
	{
		return _nbPoints > other._nbPoints;
	}

  size_t getID() const
  {
    return _id;
  }

	Action getAction() const
	{
		return _action;
	}

  int getPoints() const
  {
    return _nbPoints;
  }

	boost::shared_ptr<const Node> getPredecessor() const
	{
		return _predecessor;
	}

  boost::shared_ptr<const Map> getMap() const
  {
    return _map;
  }


private:
  static size_t nextID;
  const size_t _id;
	const boost::shared_ptr<const Node> _predecessor;
	const Action _action;
	const boost::shared_ptr<const Map> _map;
	const int _nbPoints;
};

class NodeHash : public std::unary_function<const Node*, size_t>
{
public:
  NodeHash() { }
  size_t operator()(const Node* node) const
  {
    return _mapHash(node->getMap().get());
  }
private:
  const MapHash _mapHash;
};

class NodeEqualTo : public std::binary_function<const Node*, const Node*, bool>
{
public:
  NodeEqualTo() { }
  bool operator()(const Node* node1, const Node* node2) const
  {
    return _mapEqualTo(node1->getMap().get(), node2->getMap().get());
  }
private:
  const MapEqualTo _mapEqualTo;
};

class NodeCompare : public std::binary_function<const Node*, const Node*, bool>
{
public:
  NodeCompare() { }
  bool operator()(const Node* node1, const Node* node2) const
  {
    return _mapCompare(node1->getMap().get(), node2->getMap().get());
  }
private:
  const MapCompare _mapCompare;
};